﻿using System;
using System.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using Rabbit.Model;
using System.Windows.Input;
using System.Windows.Threading;
using Rabbit.BusinessLogicLayer;
using Rabbit.Utils;
using Rabbit.Controls;
using System.Windows.Media;
namespace MicroBlogClient
{
    public abstract class PageBase : Page
    {
        public static UserSettings MySettings { get; set; }
        protected static SoundPlayer Player { get; set; }
        protected static readonly int MaxRecordsCountShowed = 10;
        protected int MessagePoolCount = 0;
        private static MainWindow mainWindow = App.Current.MainWindow as MainWindow;
        private static Dispatcher myDispatcher;
        public PageBase()
        {
            myDispatcher = this.Dispatcher;
        }

        public virtual void StartLoading()
        {
            MySettings = (App.Current.MainWindow as MainWindow).Me.UserSettings;
            Player = (App.Current.MainWindow as MainWindow).Player;   
        }

        public abstract void StopFetchingMessage();
        /// <summary>
        /// when the user click the UI updates in the main window, main window should call this
        /// method to update this pages data or UI
        /// </summary>
        public abstract void DoWork(object obj = null);
        /// <summary>
        /// if this page's status updated, it should notify the main window to do UI update
        /// </summary>
        protected abstract void NotifyMainWindowNewMessageCountChanged(int messageCount);

        public abstract void BeginInitializeMessage();

        #region Message Helper
        /// <summary>
        /// show processing message, this usually is called when a long-time run task started
        /// such as fetching data from the server
        /// </summary>
        /// <param name="message"></param>
        protected void ShowProcessingMessage(string message)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    mainWindow.showProcessingMessage(message);
                }));
        }

        protected void ShowFailedMessage(string message)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    mainWindow.showFailedMessage(message);
                }));
        }

        protected void ShowFailedMessage(MaxRatesExceededException ex)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                mainWindow.showFailedMessage(ex);
            }));
        }
        protected void ShowSuccessfulMessage(string message)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    mainWindow.showSuccessfulMessage(message);
                }));
        }

        protected void HideMessage()
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                (App.Current.MainWindow as MainWindow).hideMessage();
            }));
        }
        #endregion
      

        #region Popup User Information Helper

        protected void PopupUserInformation(User currentUser)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                (App.Current.MainWindow as MainWindow).CurrentUser = currentUser;
                (App.Current.MainWindow as MainWindow).popupUserInformation.IsOpen = true;
            }));
        }

        protected void UserHeadPicture_MouseEnter(object sender, MouseEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                (App.Current.MainWindow as MainWindow).popupUserInformation.PlacementTarget = sender as UIElement;
                if ((App.Current.MainWindow as MainWindow).popupUserInformation.IsOpen)
                {
                    (App.Current.MainWindow as MainWindow).popupUserInformation.IsOpen = false;
                }

                ListBoxItem item = Rabbit.Utils.Common.GetListBoxItemFromChild(sender as DependencyObject);

                if (item.Content.GetType() == typeof(Status))
                {
                    (App.Current.MainWindow as MainWindow).CurrentUser = (item.Content as Status).User;
                }
                else if (item.Content.GetType() == typeof(Comment))
                {
                    (App.Current.MainWindow as MainWindow).CurrentUser = (item.Content as Comment).User;
                }
                else if (item.Content.GetType() == typeof(User))
                {
                    (App.Current.MainWindow as MainWindow).CurrentUser = item.Content as User;
                }

                (App.Current.MainWindow as MainWindow).popupUserInformation.IsOpen = true;
            }), System.Windows.Threading.DispatcherPriority.Background);
        }

        protected void UserHeadPicture_MouseLeave(object sender, MouseEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                if (!mainWindow.popupUserInformation.IsMouseOver)
                {
                    mainWindow.popupUserInformation.IsOpen = false;
                }
            }), System.Windows.Threading.DispatcherPriority.Background);
        }
        #endregion

        #region command call method
        private static void ReplyToComments(object parameter)
        {
            Comment comment = parameter as Comment;

            CommentOperator operatorWindow = CommentOperator.GetInstance();
            operatorWindow.IsReplyToComment = true;
            operatorWindow.CurrentComment = comment;
            Win32.POINT pt;
            Win32.GetCursorPos(out pt);
            operatorWindow.ShowAndActivate(pt);
        }

        private static void OnUserNameClick(object param)
        {
            mainWindow.OpenUserStatusByName(param.ToString());
        }

        private static void CopyText(object param)
        {
            string text = "";
            if (param.GetType() == typeof(Comment))
            {
                Comment comment = param as Comment;
                text = comment.Text + Environment.NewLine + comment.InReplyToStatusText;
            }
            else if (param.GetType() == typeof(Status))
            {
                Status status = param as Status;
                text = status.Text + Environment.NewLine + "@" + status.InReplyToScreenName + " " + status.InReplyToStatusText;
            }
            else if (param.GetType() == typeof(string))
            {
                text = param.ToString();
            }

            if (!string.IsNullOrEmpty(text))
            {
                Clipboard.SetText(text);
                mainWindow.showSuccessfulMessage("已复制到剪贴版");
            }
        }

        private static void MakeFriend(object param)
        {
             mainWindow.showSuccessfulMessage("正在添加关注");
            long userID = long.Parse(param.ToString());
            Action makeFriends = () =>
            {
                try
                {
                    User result = UserBL.CreateFriendship(userID);
                    mainWindow.showSuccessfulMessage("关注成功");
                }
                catch (Exception)
                {
                    mainWindow.showFailedMessage("关注失败,您已经关注过此人");
                }
            };
            makeFriends.BeginInvoke(null, null);
        }

        private static void ShowUserInformation(object param)
        {
            myDispatcher.BeginInvoke(new Action(() =>
            {
                FrameworkElement element = param as FrameworkElement;

                mainWindow.CurrentUser = element.Tag as User;
                mainWindow.popupUserInformation.PlacementTarget = element;
                mainWindow.popupUserInformation.IsOpen = true;
            }), System.Windows.Threading.DispatcherPriority.Background);
        }

        private static void HideUserInformation(object param)
        {
            myDispatcher.BeginInvoke(new Action(() =>
            {
                if (!mainWindow.popupUserInformation.IsMouseOver)
                {
                    mainWindow.popupUserInformation.IsOpen = false;
                }
            }), System.Windows.Threading.DispatcherPriority.Background);
        }

        private static void AddStatusToFavorites(object param)
        {
            string statusID = param.ToString();
            Action addToStatusHandler = () =>
            {
                try
                {
                    Status status = StatusesBL.AddStatusToFavorites(statusID);
                    //TODO add the new favorite to local client
                    mainWindow.showSuccessfulMessage("收藏成功");
                }
                catch (MaxRatesExceededException ex)
                {
                    mainWindow.showFailedMessage(ex);
                }
                catch (Exception ex)
                {
                    LogHelper.LogError(ex);
                    mainWindow.showFailedMessage("收藏失败，请重试");
                }
            };
            addToStatusHandler.BeginInvoke(null, null);
        }

        private static void ShowLargeImage(object param)
        {
            PictureViewer pv = new PictureViewer();
            pv.PictureSource = param.ToString();
            pv.ShowActivated = true;
            pv.Show();
        }

        private static void QuickForwardStatus(object param)
        {
            Status CurrentStatus = param as Status;
            bool IsOperateOrignalStatus = CurrentStatus.InReplyToStatusId != 0;
            mainWindow.showProcessingMessage("正在转发..");

            string text =string.Format("{0} 转发微博","//@" + CurrentStatus.User.ScreenName);
            long statusID = IsOperateOrignalStatus ? CurrentStatus.InReplyToStatusId : CurrentStatus.Id;
            long userID = IsOperateOrignalStatus ? CurrentStatus.InReplyToUserId : CurrentStatus.User.Id;

            forwardStatus(IsOperateOrignalStatus, CurrentStatus, text, statusID);
        }

        private static void forwardStatus(bool IsOperateOrignalStatus, Status CurrentStatus, string text, long statusID)
        {
            Action replyorFoward = () =>
            {
                try
                {
                    Status status = StatusesBL.ForwardStatus(
                        statusID,
                        text,
                        true);

                    myDispatcher.BeginInvoke(new Action(() =>
                    {
                        if (IsOperateOrignalStatus)
                        {
                            CurrentStatus.InReplyToTransmitCount += 1;
                            status.InReplyToTransmitCount = CurrentStatus.InReplyToTransmitCount;
                        }
                        else
                        {
                            CurrentStatus.TransmitCount += 1;
                            status.InReplyToTransmitCount = CurrentStatus.TransmitCount;
                        }
                        ((Application.Current.MainWindow as MainWindow).frmFriendsStatus.Content as PageBase).DoWork(status);
                    }));

                    mainWindow.showSuccessfulMessage("转发成功");
                }
                catch (PublishAPICallTooFrequentException)
                {
                    mainWindow.showFailedMessage("您操作太频繁了，休息一下");
                }
                catch (Exception ex)
                {
                    LogHelper.LogError(ex);
                    mainWindow.showFailedMessage("转发失败，请重试");
                }
            };
            replyorFoward.BeginInvoke(null, null);
        }

        private static void ForwardOrignalStatus(object param)
        {
            OpenCommentWindow(param as Status,isForwardStatus:true,isOperatingOrignalStatus:true);
        }

        private static void ReplyOrignalStatus(object param)
        {
            OpenCommentWindow(param as Status,isReplyToStatus:true, isOperatingOrignalStatus:true);
        }

        private static void ForwardStatus(object param)
        {
            OpenCommentWindow(param as Status,isForwardStatus:true);
        }

        private static void ReplyStatus(object param)
        {
            OpenCommentWindow(param as Status,isReplyToStatus:true);
        }

        /// <summary>
        /// open comment window
        /// </summary>
        /// <param name="status">the status that to be replied or forwared</param>
        /// <param name="isForwardStatus">true to farward status, false to reply status</param>
        /// <param name="isOperatingOrignalStatus">true to operate orignal status, false to reply orignal status</param>
        private static void OpenCommentWindow(Status status, bool isForwardStatus=false,bool isReplyToStatus = false, bool isOperatingOrignalStatus=false)
        {
            CommentOperator operatorWindow = CommentOperator.GetInstance();
            operatorWindow.IsForwardStatus = isForwardStatus;
            operatorWindow.IsOperateOrignalStatus = isOperatingOrignalStatus;
            operatorWindow.IsReplyToStatus = isReplyToStatus;
            operatorWindow.CurrentStatus = status;
            Win32.POINT pt;
            Win32.GetCursorPos(out pt);
            operatorWindow.ShowAndActivate(pt); 
        }
        #endregion
        protected void menuCopyStatus_Click(object sender, RoutedEventArgs e)
        {
            string text = (sender as MenuItem).CommandParameter.ToString();
            Clipboard.SetText(text);
        }

        protected void OnUnHandledExceptionOccured(Exception ex)
        {
            ShowFailedMessage("获取数据错误");
        }

        protected void link_OnUserNameClicked(object sender, RoutedEventArgs e)
        {
            Hyperlink link = sender as Hyperlink;
            if (link == null)
            {
                link = e.OriginalSource as Hyperlink;
            }
            mainWindow.OpenUserStatusByName(link.CommandParameter.ToString());
        }
         

        protected void OnCallAPITooFrequentExceptionOccured(PublishAPICallTooFrequentException ex)
        {
            ShowFailedMessage("您操作太频繁了，休息会吧");
        }

        protected void TryPlaySound()
        {
            if (MySettings.IsPlayingSound.HasValue && MySettings.IsPlayingSound.Value)
            {
                Player.Play();
            }
        }

        protected void TryTwinkSystrayIcon(string message)
        {
            if (MySettings.IsTwinkleSysTrayIcon.HasValue && MySettings.IsTwinkleSysTrayIcon.Value)
            {
                App.TwinkleSysTrayIcon(message);
            }
        }

        protected void TryPopupMessage<T>(bool? IsPopup, Action<object, MouseButtonEventArgs> onMessageClicked,
            string MessageType, T MessageObj)
        {
            MessagePoolCount = MessagePoolCount >= 99 ? 99 : MessagePoolCount;

            NotifyMainWindowNewMessageCountChanged(MessagePoolCount);
            TryTwinkSystrayIcon("微博有更新，点击查看");
            TryPlaySound();

            if (!IsPopup.HasValue)
            {
                return;
            }
            if (!IsPopup.Value)
            {
                return;
            }

            PopupdMessage popup = new PopupdMessage();
            popup.MessageClicked = onMessageClicked;
            popup.MessageCount = MessagePoolCount;
            popup.MessageType = MessageType;

            string UserName = string.Empty;
            long UserID = 0;
            string UserPictureUrl = string.Empty;
            string Message = string.Empty;

            Type objType = typeof(T);
            if (objType == typeof(Status))
            {
                Status tempStatus = MessageObj as Status;
                UserName = tempStatus.User.ScreenName;
                UserID = tempStatus.User.Id;
                UserPictureUrl = tempStatus.User.ProfileImageUrl;
                Message = tempStatus.Text;
                Message += string.IsNullOrEmpty(tempStatus.InReplyToStatusText) ? ""
                    : Environment.NewLine + "//" 
                    + tempStatus.InReplyToScreenName 
                    + ":" 
                    + tempStatus.InReplyToStatusText;
            }
            else if (objType == typeof(Comment))
            {
                Comment tempStatus = MessageObj as Comment;
                UserName = tempStatus.User.ScreenName;
                UserID = tempStatus.User.Id;
                UserPictureUrl = tempStatus.User.ProfileImageUrl;
                Message = tempStatus.Text;
                Message += string.IsNullOrEmpty(tempStatus.InReplyToStatusText) ? ""
                    : Environment.NewLine + "//"
                    + tempStatus.InReplyToScreenName
                    + ":"
                    + tempStatus.InReplyToStatusText;
            }
            else if (objType == typeof(Letter))
            {
                Letter temp = MessageObj as Letter;
                UserName = temp.SenderScreenName;
                UserID = temp.SenderId;
                UserPictureUrl = temp.Sender.ProfileImageUrl;
                Message = temp.Text;
            }
            popup.UserName = UserName;
            popup.UserID = UserID;
            popup.UserPictureUrl = UserPictureUrl;
            popup.Message = Message;
            popup.Show();
        }
         
        //TODO this need to be refactored later to make good use of principle of OOP
        public abstract void pager_OnFirstPageClick(object sender, System.Windows.RoutedEventArgs e);
        public abstract void pager_OnPreviousePage(object sender, System.Windows.RoutedEventArgs e);
        public abstract void pager_OnNextPageClick(object sender, System.Windows.RoutedEventArgs e);

        #region commands

        //copy command
        public AlwaysCanExecuteCommand CopyCommand
        {
            get { return (AlwaysCanExecuteCommand)GetValue(CopyCommandProperty); }
            set { SetValue(CopyCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CopyCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CopyCommandProperty =
            DependencyProperty.Register("CopyCommand",
                typeof(AlwaysCanExecuteCommand),
                typeof(PageBase),
                  new UIPropertyMetadata(
                      new AlwaysCanExecuteCommand(CopyText))
                );

        public AlwaysCanExecuteCommand OpenUserPageCommand
        {
            get { return (AlwaysCanExecuteCommand)GetValue(OpenUserPageCommandProperty); }
            set { SetValue(OpenUserPageCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for OpenUserPageCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OpenUserPageCommandProperty =
            DependencyProperty.Register("OpenUserPageCommand",
                                typeof(AlwaysCanExecuteCommand),
                                typeof(PageBase),
                                new UIPropertyMetadata(
                                                    new AlwaysCanExecuteCommand(OnUserNameClick))
                                );
         
        public AlwaysCanExecuteCommand ReplyToCommentsCommand
        {
            get { return (AlwaysCanExecuteCommand)GetValue(ReplyToCommentsCommandProperty); }
            set { SetValue(ReplyToCommentsCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ReplyToCommentsCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ReplyToCommentsCommandProperty =
            DependencyProperty.Register("ReplyToCommentsCommand",
                typeof(AlwaysCanExecuteCommand),
                typeof(PageBase),
                new UIPropertyMetadata(new AlwaysCanExecuteCommand(ReplyToComments)));

        public AlwaysCanExecuteCommand ShowUserInformationCommand
        {
            get { return (AlwaysCanExecuteCommand)GetValue(ShowUserInformationCommandProperty); }
            set { SetValue(ShowUserInformationCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ShowUserInformationCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ShowUserInformationCommandProperty =
            DependencyProperty.Register("ShowUserInformationCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(ShowUserInformation)));
         
    public AlwaysCanExecuteCommand HideUserInformationCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(HideUserInformationCommandProperty); }
        set { SetValue(HideUserInformationCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for HideUserInformationCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty HideUserInformationCommandProperty = 
        DependencyProperty.Register("HideUserInformationCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(HideUserInformation)));

    public AlwaysCanExecuteCommand ShowLargeImageCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(ShowLargeImageCommandProperty); }
        set { SetValue(ShowLargeImageCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ShowLargeImageCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ShowLargeImageCommandProperty =
        DependencyProperty.Register("ShowLargeImageCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(ShowLargeImage)));

    public AlwaysCanExecuteCommand QuickForwardStatusCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(QuickForwardStatusCommandProperty); }
        set { SetValue(QuickForwardStatusCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for QuickForwardStatusCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty QuickForwardStatusCommandProperty =
        DependencyProperty.Register("QuickForwardStatusCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(QuickForwardStatus)));
         
    public AlwaysCanExecuteCommand ForwardOrignalStatusCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(ForwardOrignalStatusCommandProperty); }
        set { SetValue(ForwardOrignalStatusCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ForwardOrignalStatusCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ForwardOrignalStatusCommandProperty =
        DependencyProperty.Register("ForwardOrignalStatusCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(ForwardOrignalStatus)));
         
    public AlwaysCanExecuteCommand ReplyOrignalStatusCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(ReplyOrignalStatusCommandProperty); }
        set { SetValue(ReplyOrignalStatusCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ReplyOrignalStatusCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ReplyOrignalStatusCommandProperty =
        DependencyProperty.Register("ReplyOrignalStatusCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(ReplyOrignalStatus)));
         
    public AlwaysCanExecuteCommand ForwardStatusCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(ForwardStatusCommandProperty); }
        set { SetValue(ForwardStatusCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ForwardStatusCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ForwardStatusCommandProperty =
        DependencyProperty.Register("ForwardStatusCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(ForwardStatus)));

    public AlwaysCanExecuteCommand ReplyStatusCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(ReplyStatusCommandProperty); }
        set { SetValue(ReplyStatusCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ReplyStatusCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ReplyStatusCommandProperty =
        DependencyProperty.Register("ReplyStatusCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(ReplyStatus)));

    public AlwaysCanExecuteCommand AddStatusToFavoritesCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(AddStatusToFavoritesCommandProperty); }
        set { SetValue(AddStatusToFavoritesCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for AddStatusToFavoritesCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AddStatusToFavoritesCommandProperty =
        DependencyProperty.Register("AddStatusToFavoritesCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(AddStatusToFavorites)));
         
    public AlwaysCanExecuteCommand MakeFriendCommand
    {
        get { return (AlwaysCanExecuteCommand)GetValue(MakeFriendCommandProperty); }
        set { SetValue(MakeFriendCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MakeFriendCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MakeFriendCommandProperty =
        DependencyProperty.Register("MakeFriendCommand", typeof(AlwaysCanExecuteCommand), typeof(PageBase), new UIPropertyMetadata(new AlwaysCanExecuteCommand(MakeFriend)));


        #endregion
    }
}
